package com.youlu.campus.admin.auth.shiro.credentials;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.admin.auth.shiro.token.AuthToken;
import com.youlu.campus.admin.auth.shiro.token.AuthType;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SaltedAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by zhuhuaiqi on 2018/03/14.
 *
 * @author zhuhuaiqi
 */
public class AuthCredentialsMatcher extends HashedCredentialsMatcher {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AuthCredentialsService accessCredentialsService;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {

//        logger.debug(":>>> doCredentialsMatch AuthenticationToken:{}, AuthenticationInfo:{}", JSON
//                .toJSONString(token), JSON.toJSONString(info));

        AuthToken authToken = (AuthToken) token;
        authToken.setUpdateTtl(true);


        logger.debug(":>>> 登陆鉴权信息:doCredentialsMatch token:{}, info:{}", JSON.toJSONString(token
                .getCredentials()), JSON.toJSONString(info.getCredentials()));


        if (AuthType.ACCESS_CREDENTIALS.equals(authToken.getAuthType())) {
            byte[] bytes = toBytes(token.getCredentials());
            return accessCredentialsService.checkAccessToken(bytes, info, authToken.isUpdateTtl());
        }

        Object tokenHashedCredentials = hashProvidedCredentials(token, info);
        Object accountCredentials = (info);
//        logger.debug(":>>> doCredentialsMatch tokenHashedCredentials:{}, accountCredentials:{}",
//                tokenHashedCredentials, accountCredentials);
        boolean matches = equals(tokenHashedCredentials, accountCredentials);

        //boolean matches = super.doCredentialsMatch(token, info);
//        logger.debug("doCredentialsMatch matches:{}", matches);
        //TODO:
        if (true) {

//        if (matches && AuthType.USERNAME_PASSWORD.equals(authToken.getAuthType())) {
            String accessToken = accessCredentialsService.genAccessToken(authToken);
            //String accessToken = accessTokenService.genAccessToken(authToken.getUsername());
//            logger.debug("doCredentialsMatch gen accessToken:{}", accessToken);
            authToken.setAccessToken(accessToken);
        }

        //logger.debug("doCredentialsMatch accessTokenService:{}", accessTokenService);
        //TODO:
//        return matches;
        return true;
    }

    @Override
    protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) {
        Object salt = null;
        if (info instanceof SaltedAuthenticationInfo) {
            logger.debug("hashProvidedCredentials info instanceof SaltedAuthenticationInfo");
            salt = ((SaltedAuthenticationInfo) info).getCredentialsSalt();
            logger.debug("hashProvidedCredentials salt:{}", JSON.toJSONString(salt));
        } else {
            //retain 1.0 backwards compatibility:
            //logger.debug("hashProvidedCredentials isHashSalted:{}", isHashSalted());
            if (isHashSalted()) {
                //logger.debug("hashProvidedCredentials getSalt:{}", JSON.toJSONString(token
                // .getPrincipal()));
                salt = getSalt(token);
            }
        }
        return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations());
    }

    @Override
    protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
        logger.debug("hashProvidedCredentials credentials:{}, salt:{}, hashIterations:{}", JSON
                .toJSONString(credentials), JSON.toJSONString(salt), hashIterations);
        String hashAlgorithmName = assertHashAlgorithmName();
        return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
    }

    private String assertHashAlgorithmName() throws IllegalStateException {
        String hashAlgorithmName = getHashAlgorithmName();
        logger.debug("assertHashAlgorithmName :{}", hashAlgorithmName);
        if (hashAlgorithmName == null) {
            String msg = "Required 'hashAlgorithmName' property has not been set.  This is " +
                    "required to execute " +
                    "the hashing algorithm.";
            throw new IllegalStateException(msg);
        }
        return hashAlgorithmName;
    }
}
